/*
 * Licensed to the Apache Software Foundation (ASF) under one or more
 * contributor license agreements.  See the NOTICE file distributed with
 * this work for additional information regarding copyright ownership.
 * The ASF licenses this file to You under the Apache License, Version 2.0
 * (the "License"); you may not use this file except in compliance with
 * the License.  You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package org.apache.dubbo.rpc.service;

import java.util.concurrent.CompletableFuture;

/**
 * Generic service interface
 * 泛化接口调用方式主要用于客户端没有 API 接口及模型类元的情况，
 * 参数及返回值中的所有 POJO 均用 Map 表示，
 *
 * 通常用于框架集成，比如：实现一个通用的服务测试框架，可通过 GenericService 调用所有服务实现。
 *
 *
 * 请注意，消费消费者没有 API 接口 及 模型类元。那就是说，Dubbo 在泛化引用中，需要做两件事情:
 * 1、没有 API 接口，所以提供一个泛化服务接口
 * 2、没有 模型类元，所以方法参数和方法返回若是 POJO ( 例如 User 和 Order 等 ) ，需要转换处理
 *
 *
 * 有两种处理方式：
 * 第一种：
 * 服务提供者不做任何处理，正常的方式
 *
 * 服务消费者：
 *
 * 配置如下：
 * <dubbo:reference id="demoService"  interface="com.alibaba.dubbo.demo.DemoService" generic="true" />
 *
 * 代码如下：
 * ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext(new String[]{"META-INF/spring/dubbo-demo-consumer.xml"});
 *
 * GenericService genericService = (GenericService) context.getBean("demoService");
 * Object result = genericService.$invoke("say01", new String[]{"java.lang.String"}, new Object[]{"123"});
 * System.out.println("result: " + result);
 *
 * @export
 */
public interface GenericService {

    /**
     * Generic invocation
     *
     * @param method         Method name, e.g. findPerson. If there are overridden methods, parameter info is
     *                       required, e.g. findPerson(java.lang.String)
     * @param parameterTypes Parameter types
     * @param args           Arguments
     * @return invocation return value
     * @throws GenericException potential exception thrown from the invocation
     */
    Object $invoke(String method, String[] parameterTypes, Object[] args) throws GenericException;

    default CompletableFuture<Object> $invokeAsync(String method, String[] parameterTypes, Object[] args) throws GenericException {
        Object object = $invoke(method, parameterTypes, args);
        if (object instanceof CompletableFuture) {
            return (CompletableFuture<Object>) object;
        }
        return CompletableFuture.completedFuture(object);
    }

}